<template>
  <!-- 编辑窗口  (新增  编辑) -->
  <div class="edit-container">
    <el-dialog :model-value="props.dialogFormVisible" :title="props.id === 0 ? '添加用户' : '编辑用户'" @close="CancelFn">
      <el-form :model="form" :rules="rules" ref="ruleFormRef" scroll-to-error>
        <el-form-item label="账号 : " prop="username">
          <el-input v-model="form.username" autocomplete="off" placeholder="请输入账号" />
        </el-form-item>
        <el-form-item label="姓名 : " prop="nickName">
          <el-input v-model="form.nickName" autocomplete="off" placeholder="请输入姓名" />
        </el-form-item>
        <el-form-item label="邮箱 : " prop="email">
          <el-input v-model="form.email" autocomplete="off" placeholder="请输入邮箱" />
        </el-form-item>
        <el-form-item label="密码 : " prop="password">
          <el-input v-model="form.password" type="password" autocomplete="off" placeholder="请输入密码" />
        </el-form-item>
        <el-form-item label="备注 : " prop="note">
          <el-input v-model="form.note" type='textarea' :row="5" resize="none" autocomplete="off" placeholder="请输入备注" />
        </el-form-item>
        <el-form-item label="是否启用 : ">
          <el-radio-group v-model="form.status">
            <el-radio :label="1">是</el-radio>
            <el-radio :label="0">否</el-radio>
          </el-radio-group>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="CancelFn">取消</el-button>
          <el-button type="primary" @click="ConfirmFn">
            确定
          </el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import * as http from '@/request/http';
import { ElMessage, ElMessageBox, FormInstance } from 'element-plus';
import { reactive, ref, watch } from 'vue';


// 接收 父组件 传过来的 参数
const props = withDefaults(defineProps<{
  // dialogFormVisible 控制窗口的显示/隐藏  由父组件传递过来
  dialogFormVisible: boolean,
  // 当前用户的id (如果是0,表示新增; 如果不为0,表示编辑)
  id: number,
}>(), {
  dialogFormVisible: false,  // 默认值
  id: 0,   // 设置id 默认值
})

// form表单的数据
const form = reactive({
  username: '',
  nickName: '',
  email: '',
  password: '',
  note: '',
  status: 1,
  id: 0
})

const ruleFormRef = ref<FormInstance>();


// 自定义  邮箱校验  规则
const validateEmail = (_rule: any, value: any, callback: any) => {
  const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
  if (!emailRegex.test(value)) {
    // 如果 邮箱格式不符合 定义的邮箱校验 正则表达式  提醒用户重新输入
    callback(new Error('邮箱格式不正确,请重新输入!'));
  } else {
    callback()
  }
}

// 表单校验规则
const rules = reactive({
  // 普通的 必填 校验规则
  username: [{ required: true, message: '请输入账号!', trigger: 'blur' }],
  nickName: [{ required: true, message: '请输入姓名!', trigger: 'blur' }],
  // 自定义校验密码 规则
  password: [
    { required: true, message: '请输入密码!', trigger: 'blur' },
    // { validator: validatePassword, trigger: 'blur' }
  ],
  // 自定义校验邮箱 规则
  email: [
    { required: true, message: '请输入邮箱!', trigger: 'blur' },
    { validator: validateEmail, trigger: 'blur' }
  ],
})

const emits = defineEmits<{
  (e: 'cancel'): void;
  (e: 'confirm'): void;
}>()

// 点击 编辑/新增窗口的 "取消按钮"  以及  "窗口右上角的 X 叉号"
const CancelFn = () => {
  // 关闭窗口
  emits('cancel');   // 调用cancel自定义事件  父组件监听cancel自定义事件 执行相应回调函数  并关闭窗口
}

// 添加 的  二次确认 弹窗
const addFn = () => {
  ElMessageBox.confirm(
    '此操作将添加当前用户信息,是否继续?',
    '提示',
    {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning',
    }
  ).then(() => {
    // 发送请求 添加用户  注册用户
    http.admin.adminRegister(form).then(res => {
      if (res.code === 200) {
        // 提示用户 添加成功
        ElMessage.success('添加成功');
        emits('confirm');  // 调用confirm自定义事件  父组件监听confirm自定义事件 执行相应回调函数  并关闭窗口
      }
    })

  }).catch(() => {
    ElMessage.warning('取消提交');
  })
}

// 编辑 的 二次确认 弹窗
const editFn = () => {
  ElMessageBox.confirm(
    '此操作将修改当前用户信息,是否继续?',
    '提示',
    {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning',
    }
  ).then(() => {
    // 发送请求 编辑指定用户的信息
    http.admin.updateAdminInfoById(form).then(res => {
      if (res.code === 200) {
        // 提示用户 修改成功
        ElMessage.success('修改成功');
        emits('confirm');  // 调用confirm自定义事件  父组件监听confirm自定义事件 执行相应回调函数  并关闭窗口
      }
    })

  }).catch(() => {
    ElMessage.warning('取消提交');
  })
}

// 点击 编辑/新增窗口的 "确定按钮"
const ConfirmFn = () => {
  // 提交表单  进行表单校验
  ruleFormRef.value?.validate((valid) => {
    if (valid) {
      console.log('submit!...表单验证通过!');
      // 判断当前是 新增(0) 还是 编辑(!=0)
      if (props.id === 0) {
        // 新增
        addFn();
      } else {
        // 编辑
        editFn();
      }
    } else {
      console.log('error submit!....表单验证失败!')
      return false
    }
  })
}

// watch 监createTime听 当前用户id
watch(
  () => props.id,
  (val) => {
    console.log('watch监听到当前用户id变化了------', val);
    // 0 ===> 新增    不为0 ===> 编辑
    if (props.id != 0) {
      // 发送请求 根据id获取指定用户信息 ===>  渲染到编辑窗口上面的表单上
      http.admin.getAdminInfoById(props.id).then(res => {
        if (res.code === 200) {
          // 请求成功 更新form表单的数据
          // form = res.data   // 将失去响应性
          // 如果 直接 将res.data赋值给form  form表单的数据将失去响应性
          // 有两种方式可解决该问题 : 
          // 1. form.username = res.data.username;  将form的属性一个个进行赋值,而不是直接覆盖掉整个form对象
          // 2. 通过 Object.assign 方法  将源对象(res.data)的属性 复制到 目标对象(form)上
          Object.assign(form, res.data);
        }
      })
    } else {
      console.log('用户点击了新增,需要清空表单数据');
      // 如果当前是  点击新增  那么需要把表单的数据清空
      // 清空表单数据(重置)  -- 注意 : 绑定了prop的才会被清空!
      ruleFormRef.value?.resetFields();
    }
  }
)
// Object.assign 的 语法 :
/*
    Object.assign(target, ...sources);

      target：目标对象，将要接收属性的对象。
      sources：一个或多个源对象，从中复制属性到目标对象。
      Object.assign() 方法会按照参数的顺序将源对象的可枚举属性复制到目标对象上，并返回目标对象。

      当复制属性时，如果多个源对象具有相同的属性名，则后面的属性值会覆盖前面的属性值。
      如果目标对象本身已经有同名的属性，那么这个属性的值也会被覆盖。
      需要注意的是，Object.assign() 方法是浅拷贝，即只复制对象的引用。
      如果源对象的属性值是一个对象引用，那么目标对象得到的属性值也将是同一个引用。
      这意味着在修改目标对象的属性值时，源对象的属性值也会受到影响。
      另外，Object.assign() 方法只会拷贝源对象的自身可枚举属性。它不会复制继承的属性、不可枚举属性或 Symbol 类型的属性。
 */


</script>

<style scoped lang="less">
// .edit-container {
//   background-color: #fcf;
// }
</style>